﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Wimm.Common.Entities;
using Wimm.Common.Interfaces.Repositories;
using Wimm.Common.Interfaces.Services;
using Wimm.Common.Interfaces.Utils;


namespace Wimm.BusinessLogic.Services
{
    public class ExpenseService : IExpenseService
    {
        private IExpenseRepository _expensRepositroy;
        private IIconRepository    _iconsRepo;
        public ExpenseService(IExpenseRepository expenceRepo, IIconRepository iconsRepo)
        {
            _expensRepositroy = expenceRepo;
            _iconsRepo        = iconsRepo;
        }

        //testing
        public async Task<IPagedResult<Expense>> LoadExpenses(IPagedRequest<Expense> request)
        {
            return await _expensRepositroy.LoadPaged(request);
        }

        public async Task<IEnumerable<ExpenseCategory>> LoadCategories(int? parentId)
        {
            return await _expensRepositroy.LoadAllCategories(parentId);
        }

        public async Task<IReadOnlyDictionary<int, Icon>> LoadCategoryIcons()
        {
            Dictionary<int, Icon> res = new Dictionary<int, Icon>();

            IEnumerable<Icon> iconsFromDb = await _iconsRepo.LoadAllIcons();

            foreach (Icon i in iconsFromDb)
                res.Add(i.Id, i);

            return res;
        }
        public async Task<Expense> InsertExpense(Expense newExpence)
        {
            return await _expensRepositroy.InsertExpense(newExpence);
        }
        public async Task<Expense> EditExpense(Expense expence)
        {
            return await _expensRepositroy.EditExpense(expence);
        }

        public async Task<IEnumerable<KeyValuePair<ExpenseCategory, decimal>>> LoadExpenseGroups(DateTime? from, DateTime? to, int userId, bool detailed)
        {
            IReadOnlyCollection<CategoryGroup> expensesGroup = await _expensRepositroy.LoadGrouped(from, to, userId);
            Dictionary<ExpenseCategory, decimal> totalSpent = new Dictionary<ExpenseCategory, decimal>();

            if (detailed)
            {
                foreach(CategoryGroup eg in expensesGroup)
                {
                    ExpenseCategory c = await _expensRepositroy.LoadCategoryById(eg.CategoryId);
                    totalSpent.Add(c, eg.Amount);
                }
            }
            else
            {
                foreach (CategoryGroup eg in expensesGroup)
                {
                    ExpenseCategory c = await _expensRepositroy.LoadRootCategory(eg.CategoryId);
                    if (totalSpent.ContainsKey(c))
                        totalSpent[c] = totalSpent[c] + eg.Amount;
                    else
                        totalSpent.Add(c, eg.Amount);
                }
            }

            return totalSpent;
        }

        public async Task<IEnumerable<Tuple<int, int, int, string>>> LoadCategories()
        {
            var result = new List<Tuple<int, int, int, string>>(); // id, parent id, nesting lvl, name
            var categories = await _expensRepositroy.LoadCategories();
            result.AddRange(categories.Where(x => x.ParentId == null).Select(x => new Tuple<int, int, int, string>(x.Id, 0, 0, x.Description)));

            for (int i = 0; i < result.Count; i++)
            {
                var index = result.IndexOf(result[i]);
                var itemChild = categories.Where(x => x.ParentId == result[i].Item1);
                if (itemChild.Count() > 0)
                {
                    result.InsertRange(index + 1, itemChild.Select(x => 
                        new Tuple<int, int, int, string>(
                            x.Id, 
                            result[i].Item1, 
                            result[i].Item3 + 1,
                            x.Description)
                        ));
                }
            }

            return result;
        }
        public async Task<DateTime> GetLimitDate(bool isMaxDate)
        {
            return await _expensRepositroy.GetLimitDate(isMaxDate);
        }

    }
}
